package com.ibuildmap;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.InfoWindow;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.geocode.GeoCodeOption;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;

import java.util.Map;

/**
 * Created by youkai on 2017/5/23.
 */
public class IbuildMapViewManager extends ViewGroupManager<TextureMapView> {

    ThemedReactContext mReactContext;
    private TextView tv_projectIconFocus;
    //是否是Marker点击,用来和InfoWindow点击做区分
    boolean isProjectMarkerClickNow = false;
    //是否点击了Marker,如果是,则不传Geo地址
    boolean isMarkerClick = false;
    DataEntity lastMarkerEntity;
    GeoCoder geoCoder;
    int onGetReverseGeoCodeResultType = OnGetReverseGeoCodeResultType.MAP_CHANGE_FINISH;

    @Override
    public String getName() {
        return "BDMap";
    }

    @Override
    protected TextureMapView createViewInstance(ThemedReactContext reactContext) {
        this.mReactContext = reactContext;
        TextureMapView mapView = new TextureMapView(reactContext);
        mapView.showZoomControls(false);

        BaiduMap baiduMap = mapView.getMap();
        baiduMap.setMyLocationEnabled(true);

        geoCoder = GeoCoder.newInstance();
        setListeners(mapView);
        return mapView;
    }

    @ReactProp(name = "mapAnnotations")
    public void setMapAnnotations(TextureMapView view, @Nullable ReadableArray options) {
        view.getMap().clear();
        for (int i = 0; i < options.size(); i++) {
            CustomOverLayMgt customOverLayOptions = new CustomOverLayMgt(
                    view,
                    Util.getDataEntity(options.getMap(i))

            );
            customOverLayOptions.draw();
        }
    }

    @ReactProp(name = "mapUpdateStatus")
    public void setMapUpdateStatus(TextureMapView view, @Nullable ReadableMap mapStatus) {
        if (mapStatus == null) {
            return;
        }

        BaiduMap curMap = view.getMap();
        if (mapStatus.hasKey("state") && mapStatus.getString("state").equalsIgnoreCase("active")) {
            view.onResume();
        }

        boolean needRefresh = false;

        MapStatus curStatus = curMap.getMapStatus();
        LatLng latLng = curStatus.target;
        float zoomLevel = curStatus.zoom;

        if (mapStatus.hasKey("locationY") && mapStatus.hasKey("locationX")) {
            needRefresh = true;
            latLng = new LatLng(mapStatus.getDouble("locationY"), mapStatus.getDouble("locationX"));
        }

        if (mapStatus.hasKey("zoomLevel")) {
            needRefresh = true;
            zoomLevel = (float) mapStatus.getDouble("zoomLevel");
        }

        if (needRefresh) {
            MapStatusUpdate update = MapStatusUpdateFactory.newLatLngZoom(latLng, zoomLevel);
            curMap.animateMapStatus(update);
        }
    }

    private void setListeners(final TextureMapView mapView) {
        if (tv_projectIconFocus == null) {
            tv_projectIconFocus = (TextView) LayoutInflater.from(mapView.getContext())
                    .inflate(R.layout.view_overlay_focus, null);
        }
        mapView.getMap().setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
            private WritableMap getEventParams(MapStatus mapStatus) {
                WritableMap writableMap = Arguments.createMap();
                WritableMap target = Arguments.createMap();
                target.putDouble("latitude", mapStatus.target.latitude);
                target.putDouble("longitude", mapStatus.target.longitude);
                writableMap.putMap("target", target);
                writableMap.putDouble("zoomLevel", mapStatus.zoom);
                return writableMap;
            }

            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus) {
                if (isProjectMarkerClickNow == true) {
                    isProjectMarkerClickNow = false;
                    return;
                }
                lastMarkerEntity = null;
                mapView.getMap().hideInfoWindow();
                sendEvent(mapView, "onMapStatusChangeStart", getEventParams(mapStatus));
            }

            @Override
            public void onMapStatusChange(MapStatus mapStatus) {
//                Log.i("OnMapStatusChange", "Changing");
            }

            @Override
            public void onMapStatusChangeFinish(MapStatus mapStatus) {
                if (tv_projectIconFocus.getVisibility() != View.GONE) {
                    tv_projectIconFocus.setVisibility(View.GONE);
                }

                if (isMarkerClick == false) {
                    onGetReverseGeoCodeResultType = OnGetReverseGeoCodeResultType.MAP_CHANGE_FINISH;
                    geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(
                            new LatLng(mapStatus.target.latitude, mapStatus.target.longitude)
                    ));
                }

                isMarkerClick = false;
                sendEvent(mapView, "onMapStatusChangeFinish", getEventParams(mapStatus));
            }
        });
        mapView.getMap().setOnMapClickListener(new BaiduMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                WritableMap writableMap = Arguments.createMap();
                WritableMap target = Arguments.createMap();
                target.putDouble("latitude", latLng.latitude);
                target.putDouble("longitude", latLng.longitude);
                mapView.getMap().hideInfoWindow();
                lastMarkerEntity = null;
                sendEvent(mapView, "onMapClick", writableMap);
            }

            @Override
            public boolean onMapPoiClick(MapPoi mapPoi) {
                return false;
            }
        });
        mapView.getMap().setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
            private WritableMap getMarkerParams(DataEntity dataEntity) {
                WritableMap writableMap = Arguments.createMap();
                writableMap.putInt("sysNo", dataEntity.getSysNo());
                writableMap.putInt("parentSysNo", dataEntity.getParentSysNo());
                writableMap.putString("areaCode", dataEntity.getAreaCode());
                writableMap.putString("areaName", dataEntity.getAreaName());
                writableMap.putInt("areaType", dataEntity.getAreaType());
                writableMap.putString("projectCode", dataEntity.getProjectCode());
                writableMap.putString("projectName", dataEntity.getProjectName());
                writableMap.putInt("projectLevel", dataEntity.getProjectLevel());
                writableMap.putInt("projectCount", dataEntity.getProjectCount());
                writableMap.putDouble("locationY", dataEntity.getLocationY());
                writableMap.putDouble("locationX", dataEntity.getLocationX());
                return writableMap;
            }

            @Override
            public boolean onMarkerClick(Marker marker) {
                isMarkerClick = true;
                Bundle extra = marker.getExtraInfo();
                if (extra == null) {
                    return false;
                }

                final DataEntity dataEntity = (DataEntity) extra.getSerializable("entity");
                final LatLng latLng = new LatLng(dataEntity.getLocationY(), dataEntity.getLocationX());

                if (dataEntity.isProject()) {
                    isProjectMarkerClickNow = true;
                    mapView.getMap().hideInfoWindow();

                    if (lastMarkerEntity != null && lastMarkerEntity.getSysNo() == dataEntity.getSysNo()) {
                        lastMarkerEntity = null;
                        WritableMap writableMap = Arguments.createMap();
                        WritableMap target = Arguments.createMap();
                        target.putDouble("latitude", latLng.latitude);
                        target.putDouble("longitude", latLng.longitude);
                        sendEvent(mapView, "onMapClick", writableMap);
                        return false;
                    } else {
                        lastMarkerEntity = dataEntity;
                        toCenter(mapView, latLng, true);

                        //画当前选中marker的覆盖层
                        if (dataEntity.getProjectLevel() == 1) {
                            tv_projectIconFocus.setBackgroundResource(R.drawable.import_building_focus);
                        } else {
                            tv_projectIconFocus.setBackgroundResource(R.drawable.building_focus);
                        }

                        BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromView(tv_projectIconFocus);
                        InfoWindow infoWindow = new InfoWindow(bitmapDescriptor, latLng, 10, new InfoWindow.OnInfoWindowClickListener() {
                            @Override
                            public void onInfoWindowClick() {
                                mapView.getMap().hideInfoWindow();
                                lastMarkerEntity = null;
                                afterMarkerClick(mapView, dataEntity);
                            }
                        });
                        tv_projectIconFocus.setVisibility(View.GONE);
                        mapView.getMap().showInfoWindow(infoWindow);
                    }

                    afterMarkerClick(mapView, dataEntity);
                } else {
                    toCenter(mapView, latLng, false);
                    sendEvent(mapView, "onDataSelect", getMarkerParams(dataEntity));
                }

                return false;
            }
        });
        geoCoder.setOnGetGeoCodeResultListener(new OnGetGeoCoderResultListener() {
            private WritableMap getReverseGeoCodeEventParams(ReverseGeoCodeResult reverseGeoCodeResult) {
                WritableMap writableMap = Arguments.createMap();
                ReverseGeoCodeResult.AddressComponent addressDetail = reverseGeoCodeResult.getAddressDetail();
                if (addressDetail != null) {
                    MapStatus mapStatus = mapView.getMap().getMapStatus();
                    WritableMap target = Arguments.createMap();
                    target.putDouble("latitude", mapStatus.target.latitude);
                    target.putDouble("longitude", mapStatus.target.longitude);
                    writableMap.putMap("target", target);
                    writableMap.putDouble("zoomLevel", mapStatus.zoom);

                    WritableMap address = Arguments.createMap();
                    address.putString("province", addressDetail.province);
                    address.putString("city", addressDetail.city);
                    address.putString("district", addressDetail.district);

                    writableMap.putMap("address", address);
                }
                return writableMap;
            }

            @Override
            public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {

            }

            @Override
            public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
                sendEvent(mapView, "onGetReverseGeoCodeResult", getReverseGeoCodeEventParams(reverseGeoCodeResult));
            }
        });
    }

    private void afterMarkerClick(TextureMapView mapView, DataEntity dataEntity) {
        /**单独通知Finish事件,用来绘制ProjectDetail*/
        MapStatus mapStatus = mapView.getMap().getMapStatus();
        WritableMap writableMap = Arguments.createMap();
        WritableMap target = Arguments.createMap();
        target.putDouble("latitude", mapStatus.target.latitude);
        target.putDouble("longitude", mapStatus.target.longitude);
        writableMap.putMap("target", target);
        writableMap.putDouble("zoomLevel", mapStatus.zoom);
        writableMap.putString("projectCode", dataEntity.getProjectCode());

        sendEvent(mapView, "onProjectSelect", writableMap);
    }

    private void toCenter(TextureMapView mapView, LatLng latLng, boolean animate) {
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng);
        if (animate) {
            mapView.getMap().animateMapStatus(mMapStatusUpdate);
        } else {
            mapView.getMap().setMapStatus(mMapStatusUpdate);
        }
    }

    /**
     * @param eventName
     * @param params
     */
    private void sendEvent(TextureMapView mapView, String eventName, @Nullable WritableMap params) {
        WritableMap event = Arguments.createMap();
        event.putMap("params", params);
        event.putString("type", eventName);
        mReactContext
                .getJSModule(RCTEventEmitter.class)
                .receiveEvent(mapView.getId(),
                        "topChange",
                        event);
    }
}